
Imports System.IO
Imports System.Threading

Public Module consoleApplication

    Public Event applicationShutdown()

#If Not (PocketPC OrElse Smartphone) Then

    Public Const infileIdentify As String = "{{__INFILEID__}}"
    Public Const outfileIdentify As String = "{{__OUTFILEID__}}"

    Public Function ShellEx(ByVal cmd As String, ByVal infile As String, ByVal outfile As String, _
                            Optional ByVal infileIdentify As String = consoleApplication.infileIdentify, _
                            Optional ByVal outfileIdentify As String = consoleApplication.outfileIdentify, _
                            Optional ByVal shellIOIdentify As String = "/-", _
                            Optional ByVal style As Microsoft.VisualBasic.AppWinStyle = AppWinStyle.MinimizedFocus, _
                            Optional ByVal wait As Boolean = True, _
                            Optional ByVal timeout As Int32 = -1) As Int32
        On Error Resume Next
        Dim infileReal As String = Nothing
        Dim outfileReal As String = Nothing
        Dim rtn As Int32

        If infile = shellIOIdentify Then
            infileReal = createGUID()
            Dim writer As TextWriter = Nothing
            writer = New StreamWriter(New FileStream(infileReal, FileMode.Create, FileAccess.Write, FileShare.Read))
            Dim input As String = Nothing
            input = Console.ReadLine()
            While Not input Is Nothing AndAlso Not consoleExtSignal()
                writer.WriteLine(input)
                input = Console.ReadLine()
            End While
            closestream(writer)
        Else
            infileReal = infile
        End If

        If Not consoleExtSignal() Then
            If outfile = shellIOIdentify Then
                outfileReal = createGUID()
            Else
                outfileReal = outfile
            End If

            cmd = cmd.Replace(infileIdentify, infileReal)
            cmd = cmd.Replace(outfileIdentify, outfileReal)
            rtn = Shell(cmd, AppWinStyle.Hide, wait, timeout)

            If outfile = shellIOIdentify Then
                Dim reader As TextReader = Nothing
                reader = New StreamReader(New FileStream(outfileReal, FileMode.Open, FileAccess.Read))
                Dim input As String = Nothing
                input = reader.ReadLine()
                While Not input Is Nothing AndAlso Not consoleExtSignal()
                    Console.WriteLine(input)
                    input = reader.ReadLine()
                End While
                closestream(reader)
                File.Delete(outfileReal)
            End If
        End If

        If infile = shellIOIdentify Then
            File.Delete(infileReal)
        End If
        Return rtn
    End Function

    Public Const consoleIOArgument As String = "/-"

    Public Function initialInput(ByVal argument As String, ByRef input As TextReader) As Boolean
        On Error Resume Next

        If strsame(argument, consoleIOArgument, False) Then
            input = Console.In
        Else
            input = New StreamReader(New FileStream(argument, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
        End If

        Return Not input Is Nothing
    End Function

    Public Function initialOutput(ByVal argument As String, ByRef output As TextWriter) As Boolean
        On Error Resume Next

        If strsame(argument, consoleIOArgument, False) Then
            output = Console.Out
        Else
            output = New StreamWriter(New FileStream(argument, FileMode.Create, FileAccess.Write, FileShare.Read))
        End If

        Return Not output Is Nothing
    End Function

#End If

    Public unhandledExceptionHandler As UnhandledExceptionDelegate = Nothing
    Public errorhandleflushTimer3Index As Guid = Nothing

    Public Sub startmainBase(Optional ByVal unhandledExceptHandler As UnhandledExceptionDelegate = Nothing, _
                             Optional ByVal logfile As String = Nothing)
#If Not PocketPC AndAlso Not Smartphone Then
        registerConsoleExtHandle()
#End If
        errorHandle.initial(ifoper(isemptystring(logfile), defaultLogFilename(), logfile))
        If Not isdebugmode() Then
            unhandledExceptionHandler = unhandledExceptHandler
            registerUnhandledException(unhandledExceptionHandler)
        End If
        destructor.start()

        raiseError(buildInfo2)
    End Sub

    Public Sub finishmainBase()
        RaiseEvent applicationShutdown()
        destructor.stop()
        deleteDirectory(filesystem.temppath())
        'safe to call it here, if no counters used, counter will do nothing.
        counter.finalize()
        errorHandle.finalize()
#If Not PocketPC AndAlso Not Smartphone Then
        consoleExtHandleFinish()
#End If
    End Sub

#If RETIRED Then
    Private mutex As Mutex = Nothing
#End If
    Private lock As Object = Nothing

    Sub New()
#If RETIRED Then
        Mutex = New Mutex()
#End If
        lock = New Object()
    End Sub

    Public Sub lockConsoleOutput()
#If RETIRED Then
        assert(Mutex.WaitOne(), "cannot lock console mutex.")
#End If
        Monitor.Enter(lock)
    End Sub

    Public Sub releaseConsoleOutput()
#If RETIRED Then
        Mutex.ReleaseMutex()
#End If
        Monitor.Exit(lock)
    End Sub

    Public Sub lockConsoleErrorOutput()
        lockConsoleOutput()
    End Sub

    Public Sub releaseConsoleErrorOutput()
        releaseConsoleOutput()
    End Sub

    Public Sub writeConsole(ByVal s As String)
        lockConsoleOutput()
        Console.Write(s)
        releaseConsoleOutput()
    End Sub

    Public Sub writeConsoleError(ByVal s As String)
        lockConsoleErrorOutput()
        Console.Error.Write(s)
        releaseConsoleErrorOutput()
    End Sub

    Public Sub writeConsoleline(ByVal s As String)
        writeConsole(s + newline.incode())
    End Sub

    Public Sub writeConsoleErrorline(ByVal s As String)
        writeConsoleError(s + newline.incode())
    End Sub

    Public Function ishelpArgument(ByVal args() As String)
        Return args.Length() = 0 OrElse _
                strsame(args(0), "h", False) OrElse _
                strsame(args(0), "help", False) OrElse _
                strsame(args(0), "-h", False) OrElse _
                strsame(args(0), "-help", False)
    End Function

    Public Function readConsoleline(Optional ByVal s As String = Nothing) As String
        If Not isemptystring(s) Then
            writeConsoleline(s)
        End If
        Return Console.ReadLine()
    End Function

End Module
